/**
 *
 * @param {string} bar
 * @return {string}
 */
function foo(bar: string): string {
  return `hello， ${bar}`;
}

console.log(foo('ataola'));
console.log(foo('world'));

// Symbol
const sym1 = Symbol('s1');
const sym2 = Symbol('s2');
console.log(Symbol('s1') == Symbol('s1'));
console.log(Symbol('s1') === Symbol('s1'));

// BigInt
const max: bigint = BigInt(Number.MAX_SAFE_INTEGER);
const m1: bigint = max + 1n;
const m2: bigint = max + 2n;
console.log(m1 === m2);

// enum
enum Month {
  January,
  February,
  March,
  April,
  May,
  June,
  July,
  August,
  September,
  October,
  November,
  December,
}

// function
function add(a: number): number;

function add(a: number, b: number): number;

function add(a: number, b: number, c: number, d: number): number;

function add(a: number, b?: number, c?: number, d?: number) {
  // const args = [].slice.call(arguments);
  // if (args.length === 1) {
  //   return args[0];
  // }
  // return args.reduce((a: number, b: number) => a + b, 0)

  if (a !== undefined && b !== undefined && c !== undefined && d !== undefined) {
    return a + b + c + d;
  } else if (a !== undefined && b !== undefined) {
    return a + b;
  } else if (a != undefined) {
    return a;
  }
}

console.log(add(1));
console.log(add(1, 2));
// add(1, 2, 3);
console.log(add(1, 2, 3, 4));

// generics
export type stateType<T> = {
  [key: string]: T;
};

function returnTypeItem<T>(param: T): T {
  return param;
}
console.log(returnTypeItem('hello world'));

function getArrayLength<T>(args: T): T {
  // console.log(args.length)
  console.log((args as unknown as Array<T>).length);
  return args;
}
console.log(getArrayLength([1, 2, 3, 4, 5]));

// function getValue(obj: object, key: string) {
//   return obj[key];
// }

function getValue<T extends object, U extends keyof T>(obj: T, key: U) {
  return obj[key];
}
const obj = { name: 'ataola', age: 25 };
console.log(getValue(obj, 'name'));
// console.log(getValue(obj, 'sex'));

interface FirstInterface {
  doSomething(): number;
}

interface SecondInterface {
  doSomethingElse(): string;
}

interface ChildInterface extends FirstInterface, SecondInterface {}
class Demo<T extends ChildInterface> {
  private genericProperty!: T;

  useT() {
    this.genericProperty.doSomething();
    this.genericProperty.doSomethingElse();
  }
}

class Demo2<T extends FirstInterface & SecondInterface> {
  private genericProperty!: T;

  useT() {
    this.genericProperty.doSomething(); // ok
    this.genericProperty.doSomethingElse(); // ok
  }
}

// function factory<T>(type: T): T {
//   return new type() // This expression is not constructable.
// }

function factory<T>(type: { new (): T }): T {
  return new type();
}

// let x: number;
// initialize();
// console.log(x + x); // 在赋值前使用了变量“x”。ts(2454)
// function initialize() {
//     x = 10;
// }

let x: number;
initialize();
console.log(x! + x!); //ok

function initialize() {
  x = 10;
}

// 索引类型

class Images {
  public src: string = 'https://www.google.com.hk/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png';
  public alt: string = '谷歌';
  public width: number = 500;
}

type propsNames = keyof Images;

type propsType = Images[propsNames];

function pick<T, K extends keyof T>(o: T, names: K[]): T[K][] {
  return names.map((n) => o[n]);
}

const user = {
  username: 'Jessica Lee',
  id: 460000201904141743,
  token: '460000201904141743',
  avatar: 'http://dummyimage.com/200x200',
  role: 'vip',
};

const res = pick(user, ['token', 'id']);

type partial<T> = { [K in keyof T]?: T[K] };

interface User {
  username: string;
  id: number;
  token: string;
  avatar: string;
  role: string;
}

type partialUser = partial<User>;

declare function f<T extends boolean>(x: T): T extends true ? string : number;

const xx = f(Math.random() < 0.5)
const y = f(false)
const z = f(true)

